package cn.wizzer.app.user.modules.service.impl;

import cn.wizzer.app.user.modules.models.enums.PayChannel;
import cn.wizzer.app.user.modules.models.enums.RechargeStatusEnum;
import cn.wizzer.app.user.modules.models.enums.WithdrawChannel;
import cn.wizzer.app.user.modules.models.enums.WithdrawStatusEnum;
import cn.wizzer.app.user.modules.models.vo.DailyReportVO;
import cn.wizzer.app.user.modules.models.vo.UserRechargeVO;
import cn.wizzer.app.user.modules.models.vo.UserWithdrawVO;
import cn.wizzer.app.user.modules.services.DailyReportService;
import cn.wizzer.app.user.modules.services.UserService;
import cn.wizzer.app.user.modules.services.account.UserRechargeService;
import cn.wizzer.app.user.modules.services.account.UserWithdrawService;
import cn.wizzer.framework.base.service.CommonDBService;
import com.alibaba.dubbo.config.annotation.Service;
import io.jsonwebtoken.lang.Collections;
import org.nutz.dao.Cnd;
import org.nutz.dao.Sqls;
import org.nutz.dao.sql.Sql;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Times;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.stream.Collectors;


@IocBean()
@Service(interfaceClass = DailyReportService.class)
public class DailyReportServiceImpl implements DailyReportService {
    @Inject
    private CommonDBService dbService;
    @Inject
    private UserService userService;
    @Inject
    private UserRechargeService rechargeService;
    @Inject
    private UserWithdrawService withdrawService;


    @Override
    public DailyReportVO data(String[] searchDate) {
        // 当天00:00
        long startZero = Times.d2TS(Times.D(searchDate[0]));
        // 当前23:59
        long endZero = Times.d2TS(Times.D(searchDate[1]));
        DailyReportVO vo = new DailyReportVO();
        // 充值数据
        this.handleRechargeData(vo, startZero, endZero);

        // 提现数据
        this.handleWithdrawData(vo, startZero, endZero);

        // 注册人数（不算游客）
        Cnd cnd = Cnd.where("ctAt", ">=", startZero)
                .and("ctAt", "<", endZero)
                .and("visitor", "=", 0)
                .and("inside", "=", 0);
        int registerNum = userService.count(cnd);
        vo.setRegisterNum(registerNum);
        return vo;
    }

    /**
     * 统计处理充值记录数据
     *
     * @param vo
     */
    private void handleRechargeData(DailyReportVO vo, long startZero, long endZero) {
        // 查询当日充值成功记录(包括后台手动，包括一人充值多次)
        Sql sql = Sqls.create("SELECT ur.userId,ur.amount,ur.status,ur.channel,ur.ctAt,sc.rate,")
                .appendSourceSql("((SELECT COUNT(*) FROM user_recharge WHERE userId = ur.userId")
                .appendSourceSql("AND channel != @channel AND status = @status AND ctAt < @startZero) > 0) AS oldRechargeUser")
                .appendSourceSql("FROM user_recharge AS ur LEFT JOIN sys_currency AS sc ON ur.currencyId = sc.id")
                .appendSourceSql("LEFT JOIN user AS u ON u.id = ur.userId")
                .appendSourceSql("WHERE status = @status and u.inside = 0 and ur.ctAt BETWEEN @startZero and @endZero")
                .setParam("channel", PayChannel.PLAT_FORM)
                .setParam("status", RechargeStatusEnum.SUCCESS)
                .setParam("startZero", startZero)
                .setParam("endZero", endZero);
        List<UserRechargeVO> list = dbService.list(UserRechargeVO.class, sql.toString());
        if (Collections.isEmpty(list)) {
            vo.setNewRechargeAmount(BigDecimal.ZERO);
            vo.setPlatFormRechargeAmount(BigDecimal.ZERO);
            vo.setOldRechargeAmount(BigDecimal.ZERO);
        } else {
            // 当天赠送记录集合--------------------------------
            List<UserRechargeVO> giveAwayList = list.stream()
                    .filter(userRecharge -> PayChannel.PLAT_FORM.equals(userRecharge.getChannel()))
                    .collect(Collectors.toList());
            // 赠送笔数
            vo.setPlatFormRechargeCount(giveAwayList.size());
            // 当天赠送人数 (channel为PLAT_FORM,根据userId去重)
            vo.setPlatFormRechargeNum(this.rechargeNum(giveAwayList));
            // 当天赠送金额(channel为PLAT_FORM)
            vo.setPlatFormRechargeAmount(this.rechargeAmount(giveAwayList));

            // 当天非赠送记录集合----------------------------------
            List<UserRechargeVO> rechargeList = list.stream()
                    .filter(userRecharge -> !PayChannel.PLAT_FORM.equals(userRecharge.getChannel()))
                    .collect(Collectors.toList());
            // 第三方充值笔数
            vo.setThirdRechargeCount(rechargeList.size());
            // 当天二次充值记录集合----------------------------------
            List<UserRechargeVO> oldRechargeList = rechargeList.stream()
                    .filter(UserRechargeVO::isOldRechargeUser)
                    .collect(Collectors.toList());
            // 当天二次充值人数(channel不为PLAT_FORM并且该用户在今天之前有‘充值成功’)
            vo.setOldRechargeNum(this.rechargeNum(oldRechargeList));
            // 当天二次充值总金额(channel不为PLAT_FORM并且该用户在今天之前有‘充值成功’)
            vo.setOldRechargeAmount(this.rechargeAmount(oldRechargeList));

            // 新充值记录集合----------------------------------
            List<UserRechargeVO> newRechargeList = rechargeList.stream()
                    .filter(userRechargeVO -> !userRechargeVO.isOldRechargeUser())
                    .collect(Collectors.toList());
            // 新充值人数(channel不为PLAT_FORM并且该用户在今天之前没有‘充值成功’的记录)
            vo.setNewRechargeNum(this.rechargeNum(newRechargeList));
            // 新充值金额
            vo.setNewRechargeAmount(this.rechargeAmount(newRechargeList));
            // 累计充值人数(根据userId去重)
            Sql totalNumSql = Sqls.create("SELECT COUNT(*) FROM")
                    .appendSourceSql("(SELECT userId FROM user_recharge AS ur")
                    .appendSourceSql("LEFT JOIN user AS u ON u.id = ur.userId")
                    .appendSourceSql("WHERE channel != 'PLAT_FORM' AND status = 'SUCCESS' AND u.inside = 0 AND ur.ctAt < @endZero")
                    .appendSourceSql("group by userId) as userIdCount")
                    .setParam("endZero", endZero);
            totalNumSql.setCallback(Sqls.callback.longValue());
            rechargeService.dao().execute(totalNumSql);
            vo.setTotalRechargeNum(totalNumSql.getLong());
        }
    }


    /**
     * 处理提现数据
     *
     * @param vo
     */
    private void handleWithdrawData(DailyReportVO vo, long startZero, long endZero) {
        // 当天提现总额(筛选status为SUCCESS,channel不为PLATFORM )
        Sql sql = Sqls.create("SELECT uw.userId,uw.amount,uw.status,uw.channel,uw.ctAt,sc.rate FROM user_withdraw AS uw")
                .appendSourceSql("LEFT JOIN sys_currency AS sc ON uw.currencyId = sc.id")
                .appendSourceSql("LEFT JOIN user AS u ON u.id = uw.userId")
                .appendSourceSql("WHERE uw.status = @status")
                .appendSourceSql("AND uw.channel != @channel")
                .appendSourceSql("AND u.inside = 0")
                .appendSourceSql("AND uw.ctAt BETWEEN @startZero AND @endZero")
                .setParam("status", WithdrawStatusEnum.SUCCESS)
                .setParam("channel", WithdrawChannel.PLATFORM)
                .setParam("startZero", startZero)
                .setParam("endZero", endZero);
        List<UserWithdrawVO> list = dbService.list(UserWithdrawVO.class, sql.toString());
        if (Collections.isEmpty(list)) {
            vo.setWithdrawAmount(BigDecimal.ZERO);
        } else {
            // 过滤手动转账
            list = list.stream()
                    .filter(userWithdraw -> !WithdrawChannel.BANK.equals(userWithdraw.getChannel()))
                    .collect(Collectors.toList());
            vo.setWithdrawNum(this.withdrawNum(list));
            vo.setWithdrawAmount(this.withdrawAmount(list));
        }
    }


    /**
     * 统计充值人数
     *
     * @param list
     * @return
     */
    private long rechargeNum(List<UserRechargeVO> list) {
        return list.stream()
                .map(UserRechargeVO::getUserId)
                .distinct()
                .count();
    }


    /**
     * 统计充值总额
     *
     * @param list
     * @return
     */
    private BigDecimal rechargeAmount(List<UserRechargeVO> list) {
        BigDecimal amount = BigDecimal.ZERO;
        if (list.size() > 0) {
            amount = list.stream()
                    .map(userRechargeVO -> userRechargeVO.getAmount().multiply(userRechargeVO.getRate()))
                    .reduce(BigDecimal::add).get();
        }
        return amount.setScale(2, RoundingMode.HALF_UP);
    }


    /**
     * 统计提现人数
     *
     * @param list
     * @return
     */
    private long withdrawNum(List<UserWithdrawVO> list) {
        return list.stream()
                .map(UserWithdrawVO::getUserId)
                .distinct()
                .count();
    }


    /**
     * 统计提现总额
     *
     * @param list
     * @return
     */
    private BigDecimal withdrawAmount(List<UserWithdrawVO> list) {
        BigDecimal amount = BigDecimal.ZERO;
        if (list.size() > 0) {
            amount = list.stream()
                    .map(userWithdrawVO -> userWithdrawVO.getAmount().multiply(userWithdrawVO.getRate()))
                    .reduce(BigDecimal::add).get();
        }
        return amount.setScale(2, RoundingMode.HALF_UP);
    }


}
